#include "stdafx.h"
#include "GameView.h"

#include <ctime>

#include "GlobalAppData.h"

#include "Camera.h"
#include "Scene.h"
#include "Node.h"

#include "SceneLoader.h"
#include "WorldData.h"

#include "DeferredPipeline.h"

#include "Graphics.h"
#include "RenderingSystem.h"
#include "MeshInstance.h"
#include "Material.h"
#include "Light.h"
#include "LoadTexture.h"

#include "PhysicsSystem.h"

//debug
#include "CollisionData.h"
#include "CollisionDetection.h"
#include "PhysicsPrimitives.h"

//gui
#include "Window.h"
#include "OnOffButton.h"

#include "RenderSettingsGui.h"

using namespace game;

void game::GameView::init( mscene::Scene * scene, mgfx::RenderingSystem * rendSys, mphys::PhysicsSystem * physSys )
{
	View::load();

	mTotalTime = 0.0f;

	mScene = scene;
	mRenderSystem = rendSys;
	mPhysicsSystem = physSys;

	float screenAspect = (float)mcore::GlobalAppData::Instance.ScreenWidth / (float)mcore::GlobalAppData::Instance.ScreenHeight;
	mCamera = &mScene->getCamera();
	//mCamera->walk(-230);
	mCamera->setLens(0.25f * PI, screenAspect, 5.0f, 15000.0f);
	mRenderSystem->setProjMatrix(mCamera->proj());

	initGui();
}

void GameView::load()
{
	return;

	View::load();

	mRenderSystem = new mgfx::RenderingSystem;
	mPhysicsSystem = new mphys::PhysicsSystem;

	mScene = new mscene::Scene(*mRenderSystem, *mPhysicsSystem);
	float screenAspect = (float)mcore::GlobalAppData::Instance.ScreenWidth / (float)mcore::GlobalAppData::Instance.ScreenHeight;
	mCamera = &mScene->getCamera();
	mCamera->walk(-230);
	mCamera->setLens(0.25f * PI, screenAspect, 5.0f, 1500.0f);
	mRenderSystem->setProjMatrix(mCamera->proj());

	mscene::Node * node = NULL;

	// spot 1
	//mgfx::SpotLightDesc sLightDesc;
	//sLightDesc.Radius = 300.0f;
	//sLightDesc.Intensity = 4.5f;
	//sLightDesc.Color = XMCOLOR3F(1.0f, 0.3f, 0.3f);
	//sLightDesc.IsCastingShadows = true;
	//sLightDesc.SpotAngleRad = PI / 8;
	//sLightDesc.Falloff = 1.0f;
	//sLightDesc.SpotFalloff = 1.0f;
	//msLight = mRenderSystem->createSpotLight(sLightDesc);
	//
	//node = new mscene::Node;
	//node->Position = XMFLOAT3(0.0f, 0.0f, 0.0f);
	//node->addGfxObject(*msLight);
	//mScene->addNode(node);


	//// spot 2
	//sLightDesc.Intensity = 3.0f;
	//sLightDesc.Radius = 200.0f;
	//sLightDesc.Color = XMCOLOR3F(0.4f, 3.0f, 0.9f);
	//sLightDesc.SpotAngleRad = PI / 3;
	//msLight = mRenderSystem->createSpotLight(sLightDesc);

	//node = new mscene::Node;
	//node->Position = XMFLOAT3(400.0f, 0.0f, 0.0f);
	//node->addGfxObject(*msLight);
	//mScene->addNode(node);

	//// spot 3
	//sLightDesc.Intensity = 4.5f;
	//sLightDesc.Radius = 250.0f;
	//sLightDesc.Color = XMCOLOR3F(0.9f, 0.1f, 0.9f);
	//sLightDesc.SpotAngleRad = PI / 4;
	//msLight = mRenderSystem->createSpotLight(sLightDesc);

	//node = new mscene::Node;
	//node->Position = XMFLOAT3(-400.0f, 0.0f, 0.0f);
	//node->addGfxObject(*msLight);
	//mScene->addNode(node);

	
	// spheres
	//mgfx::MeshInstance * mesh;
	//mesh = mRenderSystem->createMeshInstance("sphere.ms3d");
	//
	//mgfx::Material * material = mgfx::Material::create("sphereMat");
	//material->DiffuseColor = XMCOLOR4F(0.1f, 0.9f, 0.2f, 1.0f);
	//material->SpecularIntensityAndPower = XMFLOAT2(0.3f, 64.0f);
	//material->DiffuseMap = diffMap;
	//material->NormalMap = normalMap;
	//material->SpecularMap = specMap;
	//mesh->Material_ = material;

	//node = new mscene::Node;
	//node->Position = XMFLOAT3(0.0f, 0.0f, 100.0f);
	//node->addGfxObject(*mesh);
	//mScene->addNode(node);
	
	//{
	//	mesh = mRenderSystem->createMeshInstance("sponza.3ds");
	//	mMeshes.push_back(mesh);
	//	mesh->Material_ = material;

	//	node = new mscene::Node;
	//	node->Position = XMFLOAT3(-100, -100.0f, -100);
	//	XMStoreFloat4(&node->Orientation, XMQuaternionRotationRollPitchYaw(-PI / 2, 0, 0));
	//	node->Scale = XMFLOAT3(20.2, 20.2, 20.2);
	//	node->addGfxObject(*mesh);
	//	mScene->addNode(node);
	//}

	
	// static box
	//for(int i=0 ; i<10 ; i++)
	//{
	//	mesh = mRenderSystem->createMeshInstance("box.ms3d");
	//	mMeshes.push_back(mesh);
	//	mesh->Material_ = material;

	//	node = new mscene::Node;
	//	node->Position = XMFLOAT3(i*10, -50, 0);
	//	node->Scale = XMFLOAT3(0.5f, 0.5f, i==0 ? 1.5f : 0.5f);
	//	node->addGfxObject(*mesh);

	//	mphys::BoxDesc rbDesc;
	//	rbDesc.IsStatic = false;
	//	rbDesc.Density = 0.4f;
	//	rbDesc.Position = node->Position;
	//	rbDesc.Orientation = node->Orientation;
	//	rbDesc.HalfSizeX = 34 * 0.25f;
	//	rbDesc.HalfSizeY = 34 * 0.25f;
	//	rbDesc.HalfSizeZ = i==0 ? 34 * 0.75f : 34 * 0.25f;
	//	node->mRigidBody = &mPhysicsSystem->createBoxRigidBody(rbDesc);

	//	mScene->addNode(node);
	//}
	////

	//for(int i = 0; i < 1; i++)
	//{
	//	for(int j = 0; j < 1; j++)
	//	{
	//		for(int k = 0; k < 4; k++)
	//		{
	//		mesh = mRenderSystem->createMeshInstance("sphere.ms3d");
	//		mMeshes.push_back(mesh);
	//		mesh->Material_ = material;

	//		node = new mscene::Node;
	//		node->Position = XMFLOAT3((i-1) * 15 + k*5, -50.0f + k * 15, (j-1) * 15 + k*5);
	//		XMStoreFloat4(&node->Orientation, XMQuaternionRotationRollPitchYaw(0, 0, 0));
	//		node->Scale = XMFLOAT3(0.05f, 0.05f, 0.05f);
	//		node->addGfxObject(*mesh);

	//		//mphys::BoxDesc rbDesc;
	//		//rbDesc.IsStatic = false;
	//		//rbDesc.Density = 1.0f;
	//		//rbDesc.Position = node->Position;
	//		//rbDesc.Orientation = node->Orientation;
	//		//rbDesc.HalfSizeX = 34 * 0.25f;
	//		//rbDesc.HalfSizeY = 34 * 0.25f;
	//		//rbDesc.HalfSizeZ = 34 * 0.25f;
	//		//node->mRigidBody = &mPhysicsSystem->createBoxRigidBody(rbDesc);

	//		mphys::SphereDesc rbDesc;
	//		//if(i == 0 && j == 0)
	//			rbDesc.IsStatic = false;
	//		//else
	//		//	rbDesc.IsStatic = true;
	//		rbDesc.Density = 0.1f;
	//		rbDesc.Position = node->Position;
	//		rbDesc.Orientation = node->Orientation;
	//		rbDesc.Radius = 33.41f / 20.0f;
	//		node->mRigidBody = &mPhysicsSystem->createSphereRigidBody(rbDesc);

	//		mScene->addNode(node);
	//		}
	//	}
	//}

	//{ // plane
	//	mesh = mRenderSystem->createMeshInstance("plane100.3ds");
	//	mMeshes.push_back(mesh);
	//	material = mgfx::Material::create("boxMat");
	//	material->DiffuseColor = Color::WHITE;
	//	material->SpecularIntensityAndPower = XMFLOAT2(0.8f, 128.0f);
	//	material->DiffuseMap = diffMap;
	//	material->NormalMap = normalMap;
	//	material->SpecularMap = specMap;
	//	mesh->Material_ = material;

	//	node = new mscene::Node;
	//	node->Position = XMFLOAT3(0.0f, -150.0f, 0.0f);
	//	XMStoreFloat4(&node->Orientation, XMQuaternionRotationRollPitchYaw(-PI / 2, 0, 0));
	//	node->Scale = XMFLOAT3(100, 100, 100);
	//	node->addGfxObject(*mesh);

	//	mphys::PlaneDesc rbDesc;
	//	rbDesc.Position = node->Position;
	//	rbDesc.Orientation = node->Orientation;
	//	node->mRigidBody = &mPhysicsSystem->createPlaneRigidBody(rbDesc);

	//	mScene->addNode(node);


	//	mesh = mRenderSystem->createMeshInstance("plane100.3ds");
	//	mMeshes.push_back(mesh);
	//	mesh->Material_ = material;

	//	node = new mscene::Node;
	//	node->Position = XMFLOAT3(0.0f, -100.0f, -100.0f);
	//	XMStoreFloat4(&node->Orientation, XMQuaternionRotationRollPitchYaw(0, 0, 0));
	//	node->Scale = XMFLOAT3(2, 2, 2);
	//	node->addGfxObject(*mesh);

	//	rbDesc.Position = node->Position;
	//	rbDesc.Orientation = node->Orientation;
	//	node->mRigidBody = &mPhysicsSystem->createPlaneRigidBody(rbDesc);

	//	mScene->addNode(node);


	//	mesh = mRenderSystem->createMeshInstance("plane100.3ds");
	//	mMeshes.push_back(mesh);
	//	mesh->Material_ = material;

	//	node = new mscene::Node;
	//	node->Position = XMFLOAT3(0.0f, -100.0f, 100.0f);
	//	XMStoreFloat4(&node->Orientation, XMQuaternionRotationRollPitchYaw(0, PI, 0));
	//	node->Scale = XMFLOAT3(2, 2, 2);
	//	node->addGfxObject(*mesh);

	//	rbDesc.Position = node->Position;
	//	rbDesc.Orientation = node->Orientation;
	//	node->mRigidBody = &mPhysicsSystem->createPlaneRigidBody(rbDesc);

	//	mScene->addNode(node);


	//	mesh = mRenderSystem->createMeshInstance("plane100.3ds");
	//	mMeshes.push_back(mesh);
	//	mesh->Material_ = material;

	//	node = new mscene::Node;
	//	node->Position = XMFLOAT3(-100.0f, -100.0f, 0.0f);
	//	XMStoreFloat4(&node->Orientation, XMQuaternionRotationRollPitchYaw(0, PI / 2, 0));
	//	node->Scale = XMFLOAT3(2, 2, 2);
	//	node->addGfxObject(*mesh);

	//	rbDesc.Position = node->Position;
	//	rbDesc.Orientation = node->Orientation;
	//	node->mRigidBody = &mPhysicsSystem->createPlaneRigidBody(rbDesc);

	//	mScene->addNode(node);


	//	mesh = mRenderSystem->createMeshInstance("plane100.3ds");
	//	mMeshes.push_back(mesh);
	//	mesh->Material_ = material;

	//	node = new mscene::Node;
	//	node->Position = XMFLOAT3(100.0f, -100.0f, 0.0f);
	//	XMStoreFloat4(&node->Orientation, XMQuaternionRotationRollPitchYaw(0, -PI / 2, 0));
	//	node->Scale = XMFLOAT3(2, 2, 2);
	//	node->addGfxObject(*mesh);

	//	rbDesc.Position = node->Position;
	//	rbDesc.Orientation = node->Orientation;
	//	node->mRigidBody = &mPhysicsSystem->createPlaneRigidBody(rbDesc);

	//	mScene->addNode(node);
	//}
	
	
	mscene::loadScene("scene.xml", mscene::makeWorldData(mScene, mRenderSystem, mPhysicsSystem));

	

	mgfx::PointLightDesc lightDesc;
	lightDesc.Radius = 300.0f;
	lightDesc.Intensity = 2.5f;
	lightDesc.Falloff = 1.0f;
	lightDesc.Color = XMCOLOR3F(1.0f, 1.0f, 1.0f);

	//for(int i = 0; i < 8; i++)
	//	for(int j = 0; j < 8; j++)
	//	{
	//		light.Color = XMCOLOR3F(sinf(i) * 0.5f + 0.5f, cosf(j) * 0.5f + 0.5f, 0.5f);
	//		light.Position = XMFLOAT3((i-4) * 300, 0.0f, (j-4) * 300);
	//		mRenderSystem->addPointLight(light);
	//	}

	lightDesc.Radius = 500.0f;
	lightDesc.Intensity = 3.0f;
	lightDesc.Color = XMCOLOR3F(1.0f, 1.0f, 1.0f);
	//light.Position = XMFLOAT3(-100.0f, 0.0f, 1000.0f);
	//mLight = mRenderSystem->createPointLight(lightDesc);

	//node = new mscene::Node;
	//node->Position = XMFLOAT3(-100.0f, 0.0f, 1000.0f);
	//node->addGfxObject(*mLight);
	//mScene->addNode(node);

	initGui();
}

void GameView::unload()
{
	SAFE_DELETE(mRenderSettingsGui);

	SAFE_DELETE(mScene);
	SAFE_DELETE(mPhysicsSystem);
	SAFE_DELETE(mRenderSystem);

	View::unload();
}

void GameView::update(float dt)
{ 
	static float SMALL_DT = 0.0001f;
	if(mTotalTime == 0.0f)
		dt = SMALL_DT;
	mTotalTime += dt;

	//if(mPhysicsSystem->DebugFirstCollFound == false)
	//{
		mPhysicsSystem->update(dt);
	//}
	
	mScene->update(dt);
	mRenderSystem->update(dt);
}

void GameView::draw()
{
	mRenderSystem->setViewMatrix(mCamera->view());
	mRenderSystem->setEyePosition(mCamera->position());
	mRenderSystem->setViewFrustum(mCamera->Frustum_);
	mgfx::DeferredPipeline::get().render(mRenderSystem->Data, mRenderSystem->Settings);

	mGui->draw();
}

bool GameView::onWindowMessage(UINT msg, WPARAM wParam, LPARAM lParam)
{

	sendInputToGUI(msg, wParam, lParam);

	switch( msg )
	{
	case WM_MOUSEMOVE:
		{
			static bool firstTime = true;
			int mousePosX = LOWORD(lParam);
			int mousePosY = HIWORD(lParam);
			if(firstTime)
			{
				firstTime = false;
			}
			else
			{
				int diffY = mPrevMousePosY - mousePosY;
				int diffX = mPrevMousePosX - mousePosX;
				if(diffY != 0 || diffX != 0)
				{
					mScene->mouseMove(diffX, diffY);
				}
				
			}
			mPrevMousePosX = mousePosX;
			mPrevMousePosY = mousePosY;
			return true;
		}
		break;

	case WM_LBUTTONDOWN:
		{

		}
		break;

	case WM_LBUTTONUP:
		{

		}
		break;

	case WM_KEYDOWN:
		{

			return mScene->keyEvent(util::KEY_DOWN, wParam, lParam);
		}
		break;

	case WM_KEYUP:
		{
			return mScene->keyEvent(util::KEY_UP, wParam, lParam);
		}
		break;
	}
	return false;
}

void GameView::initGui()
{
	mRenderSettingsGui = new medit::RenderSettingsGui(&mRenderSystem->Settings);
	mGui->addChild(*mRenderSettingsGui->GuiWindow);

	//mgui::Window * window = new mgui::Window(mgui::Rect(20, 50, 250, 500), "Render settings");
	//mGui->addChild(window);

	//mgui::OnOffButton * button = new mgui::OnOffButton(mgui::Rect(20, 50, 120, 25), "button");
	//window->addChild(button);

	//button->addListener(mgui::OnOffButton::EVENT_STATE_CHANGED, std::bind(&GameView::receiveButtonChange, this, std::placeholders::_1));
}
